/*
 * studenAi.h
 *
 *  Created on: Jun 12, 2014
 *      Author: zeros
 */

#ifndef STUDENAI_H_
#define STUDENAI_H_

#define NORTH 0
#define EAST 1
#define SOUTH 2
#define WEST 3
#define DEBUG printf("Line: %d\n",__LINE__);

#include "mazeBase.h"

//basic struct for storing info of each cell in the maze
struct node {
	int numVisits;
	bool deadEnd;
	bool winSpace;
	struct node *north, *south, *east, *west;

};

struct mouseRapper {
	struct mouseData *mouse;
	int heading;
	struct node (*maze)[MAZE_HEIGHT];
	int x, y;
};

int checkForwardDead(struct mouseRapper *rapper)
{
	if (isWallForward(rapper->mouse))
		return 1;
	if (rapper->heading == NORTH)
	{
		if (rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == SOUTH)
	{
		if (rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == EAST)
	{
		if (rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == WEST)
	{
		if (rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	return 0;
}

int checkLeftDead(struct mouseRapper *rapper)
{
	if (isWallLeft(rapper->mouse))
		return 1;
	if (rapper->heading == NORTH)
	{
		if (rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == SOUTH)
	{
		if (rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == EAST)
	{
		if (rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == WEST)
	{
		if (rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{
			return 1;
		}
	}
	return 0;
}

int checkRightDead(struct mouseRapper *rapper)
{
	if (isWallRight(rapper->mouse))
		return 1;
	if (rapper->heading == NORTH)
	{
		if (rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == SOUTH)
	{
		if (rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == EAST)
	{
		if (rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{
			return 1;
		}
	}
	else if (rapper->heading == WEST)
	{
		if (rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			return 1;
		}
	}
	return 0;
}

int checkForwardVisits(struct mouseRapper *rapper)
{
	if (rapper->heading == NORTH)
	{
		return rapper->maze[rapper->x][rapper->y + 1].numVisits;
	}
	else if (rapper->heading == SOUTH)
	{
		return rapper->maze[rapper->x][rapper->y - 1].numVisits;
	}
	else if (rapper->heading == EAST)
	{
		return rapper->maze[rapper->x + 1][rapper->y].numVisits;
	}
	else if (rapper->heading == WEST)
	{
		return rapper->maze[rapper->x - 1][rapper->y].numVisits;
	}
}

int checkLeftVisits(struct mouseRapper *rapper)
{
	if (rapper->heading == NORTH)
	{
		return rapper->maze[rapper->x - 1][rapper->y].numVisits;
	}
	else if (rapper->heading == SOUTH)
	{
		return rapper->maze[rapper->x + 1][rapper->y].numVisits;
	}
	else if (rapper->heading == EAST)
	{
		return rapper->maze[rapper->x][rapper->y + 1].numVisits;
	}
	else if (rapper->heading == WEST)
	{
		return rapper->maze[rapper->x][rapper->y - 1].numVisits;
	}
}

int checkRightVisits(struct mouseRapper *rapper)
{
	if (rapper->heading == NORTH)
	{
		return rapper->maze[rapper->x + 1][rapper->y].numVisits;
	}
	else if (rapper->heading == SOUTH)
	{
		return rapper->maze[rapper->x - 1][rapper->y].numVisits;
	}
	else if (rapper->heading == EAST)
	{
		return rapper->maze[rapper->x][rapper->y - 1].numVisits;
	}
	else if (rapper->heading == WEST)
	{
		return rapper->maze[rapper->x][rapper->y + 1].numVisits;
	}
}

void moveForward(struct mouseRapper *rapper)
{
	if (!checkForwardDead(rapper))
	{
		moveMouseForward(rapper->mouse);
		if (rapper->heading == NORTH)
		{
			rapper->y++;
			rapper->maze[rapper->x][rapper->y].south = &(rapper->maze[rapper->x][rapper->y - 1]);
			rapper->maze[rapper->x][rapper->y - 1].north = &(rapper->maze[rapper->x][rapper->y]);

		}
		else if (rapper->heading == EAST)
		{
			rapper->x++;
			rapper->maze[rapper->x][rapper->y].west = &(rapper->maze[rapper->x - 1][rapper->y]);
			rapper->maze[rapper->x - 1][rapper->y].east = &(rapper->maze[rapper->x][rapper->y]);
		}
		else if (rapper->heading == SOUTH)
		{
			rapper->y--;
			rapper->maze[rapper->x][rapper->y].north = &(rapper->maze[rapper->x][rapper->y + 1]);
			rapper->maze[rapper->x][rapper->y + 1].south = &(rapper->maze[rapper->x][rapper->y]);
		}
		else if (rapper->heading == WEST)
		{
			rapper->x--;
			rapper->maze[rapper->x][rapper->y].east = &(rapper->maze[rapper->x + 1][rapper->y]);
			rapper->maze[rapper->x + 1][rapper->y].west = &(rapper->maze[rapper->x][rapper->y]);
		}
		rapper->maze[rapper->x][rapper->y].numVisits++;
	}
	else
		cout << "I have failed you" << endl;

}

void turnLeft(struct mouseRapper *rapper)
{
	if (rapper->heading == NORTH)
		rapper->heading = WEST;
	else
		rapper->heading--;
	turnMouseLeft(rapper->mouse);
}
void turnRight(struct mouseRapper *rapper)
{
	if (rapper->heading == WEST)
		rapper->heading = NORTH;
	else
		rapper->heading++;
	turnMouseRight(rapper->mouse);
}
void isDeadEnd(struct mouseRapper *rapper)
{ //checks surroundings tell where to go
	rapper->maze[0][0].deadEnd = false;
	if (isWallLeft(rapper->mouse) && isWallRight(rapper->mouse) && isWallForward(rapper->mouse))
	{
		rapper->maze[rapper->x][rapper->y].deadEnd = true;
	}
	if (rapper->heading == NORTH)
	{
		if (isWallLeft(rapper->mouse) && isWallRight(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{ //wall behind left right
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallLeft(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{ //wall forward left behind
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallRight(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y - 1].deadEnd == true)
		{ //wall forward right behind
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
	}
	else if (rapper->heading == SOUTH)
	{
		if (isWallLeft(rapper->mouse) && isWallRight(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallLeft(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallRight(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x][rapper->y + 1].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
	}
	else if (rapper->heading == EAST)
	{
		if (isWallLeft(rapper->mouse) && isWallRight(rapper->mouse)
				&& rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallLeft(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallRight(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x - 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
	}
	else if (rapper->heading == WEST)
	{
		if (isWallLeft(rapper->mouse) && isWallRight(rapper->mouse)
				&& rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallLeft(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
		else if (isWallRight(rapper->mouse) && isWallForward(rapper->mouse)
				&& rapper->maze[rapper->x + 1][rapper->y].deadEnd == true)
		{
			rapper->maze[rapper->x][rapper->y].deadEnd = true;
		}
	}
}

int numOptions(struct mouseRapper *rapper)
{
	int numWalls = 0;
	if (!checkForwardDead(rapper))
	{
		numWalls++;
	}
	if (!checkLeftDead(rapper))
	{
		numWalls++;
	}
	if (!checkRightDead(rapper))
	{
		numWalls++;
	}
	return numWalls;
}

void isFinish(struct mouseRapper *rapper)
{
	for (int xMaze = 0; xMaze < MAZE_HEIGHT; xMaze++)
	{
		for (int yMaze = 0; yMaze < MAZE_WIDTH; yMaze++)
		{
			if (rapper->maze[xMaze][yMaze].east != NULL)
			{
				if (rapper->maze[xMaze][yMaze].east->north != NULL)
				{
					if (rapper->maze[xMaze][yMaze].east->north->west != NULL)
					{
						if (rapper->maze[xMaze][yMaze].east->north->west->south == &(rapper->maze[xMaze][yMaze]))
						{
							rapper->maze[xMaze][yMaze].winSpace = true;
							rapper->maze[xMaze][yMaze].east->winSpace = true;
							rapper->maze[xMaze][yMaze].east->north->winSpace = true;
							rapper->maze[xMaze][yMaze].east->north->west->winSpace = true;
						}
					}
				}
			}
		}
	}
}
int mazeExplored(struct mouseRapper *rapper)
{
	int progress = 0;
	float percentComplete;
	for (int xMaze = 0; xMaze < MAZE_HEIGHT; xMaze++)
	{
		for (int yMaze = 0; yMaze < MAZE_WIDTH; yMaze++)
		{
			if (rapper->maze[xMaze][yMaze].numVisits >= 1)
			{
				progress++;
				percentComplete = (progress/400.0)*100;
			}
		}
	}
	printf("Percent Complete: %f %\n", percentComplete);
	if (progress == 400)
	{
		return 1;
	}
	return 0;
}
int reachedEnd(struct mouseRapper *rapper)
{
	if (rapper->maze[rapper->x][rapper->y].winSpace == true)
	{
		return 1;
	}
	return 0;
}

void saveMaze(FILE *maze, struct mouseRapper *rapper)
{
	int i = 0, j = 0;
	while (i <= MAZE_WIDTH - 1 && j <= MAZE_HEIGHT)
	{
		fprintf(maze, "%d %d %d %d %d %d %d %d %d\n", i, j, rapper->maze[i][j].numVisits,
				rapper->maze[i][j].deadEnd, rapper->maze[i][j].winSpace, rapper->maze[i][j].north ? 1 : 0,
				rapper->maze[i][j].south ? 1 : 0, rapper->maze[i][j].west ? 1 : 0,
				rapper->maze[i][j].east ? 1 : 0);
		if (++j >= MAZE_HEIGHT)
		{
			j = 0;
			i++;
		}
	}
	fclose(maze);
}
void loadMaze(FILE *maze, struct mouseRapper *rapper)
{
	int linkNorth = false, linkSouth = false, linkEast = false, linkWest = false;
	int tempX = 0, tempY = 0, tempNumVisits = 0;
	int tempDeadEnd = false, tempWinSpace = false;
	while (!feof(maze))
	{
		fscanf(maze, "%d %d %d %d %d %d %d %d %d\n", &tempX, &tempY, &tempNumVisits, &tempDeadEnd, &tempWinSpace,
				&linkNorth, &linkSouth, &linkWest, &linkEast);
		printf(
				"x: %d, y: %d, numVisits: %d, deadEnd: %d, winSpace: %d, linkNorth: %d, linkSouth: %d, linkEast: %d, linkWest: %d\n",
				tempX, tempY, tempNumVisits, tempDeadEnd, tempWinSpace, linkNorth, linkSouth, linkWest, linkEast);
		rapper->maze[tempX][tempY].numVisits = tempNumVisits;
		rapper->maze[tempX][tempY].deadEnd = tempDeadEnd;
		rapper->maze[tempX][tempY].winSpace = tempWinSpace;
		if (linkNorth)
		{
			rapper->maze[tempX][tempY].north = &rapper->maze[tempX][tempY + 1];
		}
		if (linkSouth)
		{
			rapper->maze[tempX][tempY].south = &rapper->maze[tempX][tempY - 1];
		}
		if (linkEast)
		{
			rapper->maze[tempX][tempY].east = &rapper->maze[tempX + 1][tempY];
		}
		if (linkWest)
		{
			rapper->maze[tempX][tempY].west = &rapper->maze[tempX - 1][tempY];
		}
	}
	fclose(maze);
}
void studentAi(struct mouseData *mouse)
{

	/////////////////////////////
	static struct node mazeNodes[MAZE_WIDTH][MAZE_HEIGHT];
	static bool first = true;
	static struct mouseRapper LLCoolMouse;
	if (first)
	{
		first = false;
		LLCoolMouse.heading = NORTH;
		LLCoolMouse.maze = mazeNodes;
		LLCoolMouse.mouse = mouse;
		LLCoolMouse.x = 0;
		LLCoolMouse.y = 0;
		FILE *mazeOpen = fopen("savedData.maz", "r");
		//loadMaze(mazeOpen, &LLCoolMouse);
	}
	isDeadEnd(&LLCoolMouse);
//	if(possWin){//second check of possible win condition
//		possWin = false;
//		if(!isWallRight(mouse)){
//			turnRight(&LLCoolMouse);
//			moveForward(&LLCoolMouse);
//			if(!isWallRight(mouse)){
//				//printf("win cond\n");
//					mouse->foundFinish = true;
//			}
//		}
//	}
	//first check of possWin Condition
	if (mazeExplored(&LLCoolMouse) && reachedEnd(&LLCoolMouse))
	{
		LLCoolMouse.heading = NORTH;
		LLCoolMouse.maze = mazeNodes;
		LLCoolMouse.mouse = mouse;
		LLCoolMouse.x = 0;
		LLCoolMouse.y = 0;
		FILE *mazeSaved = fopen("savedData.maz", "w");
		saveMaze(mazeSaved, &LLCoolMouse);
//		for(int xMaze = 0; xMaze<MAZE_HEIGHT; xMaze++){
//			for(int yMaze = 0; yMaze<MAZE_WIDTH; yMaze++){
//				LLCoolMouse.maze[xMaze][yMaze].numVisits = 0;
//				LLCoolMouse.maze[xMaze][yMaze].deadEnd = false;
//				LLCoolMouse.maze[xMaze][yMaze].winSpace = false;
//			}
//		}
		mouse->foundFinish = true;

	}
	else if (numOptions(&LLCoolMouse) >= 2)
	{
		if (!checkLeftDead(&LLCoolMouse) && !checkRightDead(&LLCoolMouse))
		{
			if (checkLeftVisits(&LLCoolMouse) <= checkRightVisits(&LLCoolMouse))
			{
				turnLeft(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
			else
			{
				turnRight(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
		}
		else if (!checkForwardDead(&LLCoolMouse) && !checkLeftDead(&LLCoolMouse))
		{
			if (checkLeftVisits(&LLCoolMouse) <= checkForwardVisits(&LLCoolMouse))
			{
				turnLeft(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
			else
			{
				moveForward(&LLCoolMouse);
			}
		}
		else if (!checkForwardDead(&LLCoolMouse) && !checkRightDead(&LLCoolMouse))
		{
			if (checkRightVisits(&LLCoolMouse) >= checkForwardVisits(&LLCoolMouse))
			{

				moveForward(&LLCoolMouse);
			}
			else
			{
				turnRight(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
		}
		else if (!checkForwardDead(&LLCoolMouse) && !checkLeftDead(&LLCoolMouse) && !checkRightDead(&LLCoolMouse))
		{
			int res =
					checkRightVisits(&LLCoolMouse) < checkLeftVisits(&LLCoolMouse)
							&& checkRightVisits(&LLCoolMouse) < checkLeftVisits(&LLCoolMouse) ?
							2 : checkForwardVisits(&LLCoolMouse) < checkLeftVisits(&LLCoolMouse);
			if (res == 0)
			{
				turnLeft(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
			else if (res == 1)
			{
				moveForward(&LLCoolMouse);
			}
			else if (res == 2)
			{
				turnRight(&LLCoolMouse);
				moveForward(&LLCoolMouse);
			}
		}

	}
	else if (!checkLeftDead(&LLCoolMouse))
	{
		turnLeft(&LLCoolMouse);
		moveForward(&LLCoolMouse);
	}
	else if (!checkForwardDead(&LLCoolMouse))
	{
		moveForward(&LLCoolMouse);
	}
	else if (!checkRightDead(&LLCoolMouse))
	{
		turnRight(&LLCoolMouse);
		moveForward(&LLCoolMouse);
	}
	else if (checkLeftDead(&LLCoolMouse) && checkRightDead(&LLCoolMouse) && checkForwardDead(&LLCoolMouse))
	{
		turnRight(&LLCoolMouse);
		turnRight(&LLCoolMouse);
		moveForward(&LLCoolMouse);
	}
	isFinish(&LLCoolMouse);
}

#endif /* STUDENAI_H_ */
